#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PDF密码移除工具

这个工具用于移除PDF文件的编辑限制（不破解打开密码）。
当PDF文件设置了编辑限制但允许打印时，可以使用此工具创建一个无限制的副本。

Author: jr-create
Version: 1.0.0
License: MIT
create: 2022-08-15
"""

import argparse
from concurrent.futures import ThreadPoolExecutor, as_completed
import os
import sys
import tkinter as tk
from tkinter import filedialog, ttk, messagebox, scrolledtext
from typing import List, Tuple, Callable, Optional
import threading
import time
from datetime import datetime
from pdf_crack_utils import pdf_crack, logger, check_folder
import queue


class BatchProcessor:
    """独立的PDF批量处理线程类"""
    
    def __init__(self, 
                 files: List[Tuple[str, str]], 
                 output_dir: str, 
                 progress_callback: Callable[[float], None] = None, 
                 status_callback: Callable[[str], None] = None, 
                 file_status_callback: Callable[[int, str], None] = None, 
                 completion_callback: Callable[[int, int], None] = None):
        """
        初始化批处理器
        
        Args:
            files: 文件路径和状态的元组列表
            output_dir: 输出目录
            progress_callback: 进度更新回调函数
            status_callback: 状态更新回调函数
            file_status_callback: 文件状态更新回调函数
            completion_callback: 处理完成回调函数
        """
        self.files = files.copy()  # 复制文件列表，避免修改原列表
        self.output_dir = output_dir
        self.progress_callback = progress_callback
        self.status_callback = status_callback
        self.file_status_callback = file_status_callback
        self.completion_callback = completion_callback
        
        # 线程控制
        self._stop_event = threading.Event()
        self._is_running = False
        self.success_count = 0
        self.fail_count = 0
        self.total_files = len(files)
        self.processed_count = 0
        
    def start(self):
        """启动批处理线程"""
        if self._is_running:
            self._update_status("批处理已在运行中")
            return
            
        self._stop_event.clear()
        self._is_running = True
        self.success_count = 0
        self.fail_count = 0
        self.processed_count = 0
        
        # 在新线程中运行批处理
        self.thread = threading.Thread(target=self._process_batch, daemon=True)
        self.thread.start()
        return self.thread
    
    def stop(self):
        """停止批处理线程"""
        if self._is_running:
            self._stop_event.set()
            self._is_running = False
            self._update_status("正在停止批处理...")
    
    def is_running(self):
        """检查批处理是否正在运行"""
        return self._is_running and self.thread and self.thread.is_alive()
    
    def _update_status(self, message: str):
        """更新状态（线程安全）"""
        if self.status_callback:
            self.status_callback(message)
    
    def _update_progress(self, progress: float):
        """更新进度（线程安全）"""
        if self.progress_callback:
            self.progress_callback(progress)
    
    def _update_file_status(self, index: int, status: str):
        """更新文件状态（线程安全）"""
        if self.file_status_callback:
            self.file_status_callback(index, status)
    
    def _process_single_file(self, file_info: Tuple[int, Tuple[str, str]]) -> bool:
        """处理单个文件
        
        Args:
            file_info: (索引, (文件路径, 状态)) 的元组
            
        Returns:
            bool: 处理是否成功
        """
        index, (file_path, status) = file_info
        
        # 检查是否应该停止
        if self._stop_event.is_set():
            return False
            
        try:
            # 更新文件状态为"处理中"
            self._update_file_status(index, "处理中")
            
            # 获取文件名和输出路径
            file_name = os.path.basename(file_path)
            base_name, ext = os.path.splitext(file_name)
            output_file = os.path.join(self.output_dir, f"{base_name}(已破解){ext}")
            
            # 执行PDF破解操作
            pdf_crack(file_path, output_file)
            
            # 更新文件状态为"成功"
            self._update_file_status(index, "成功")
            return True
            
        except Exception as e:
            error_msg = f"处理失败: {str(e)}"
            logger.error(f"文件 {file_name} 处理失败: {str(e)}")
            self._update_file_status(index, "失败")
            return False
    
    def _process_batch(self):
        """批量处理的核心逻辑"""
        try:
            self._update_status(f"开始批量处理，共 {self.total_files} 个文件")
            
            # 使用线程池处理文件
            with ThreadPoolExecutor(max_workers=min(os.cpu_count() or 2, 4)) as executor:
                # 准备任务参数
                file_tasks = [(i, file_info) for i, file_info in enumerate(self.files)]
                
                # 提交所有任务
                future_to_index = {
                    executor.submit(self._process_single_file, task): task[0] 
                    for task in file_tasks
                }
                
                # 处理完成的任务
                for future in as_completed(future_to_index):
                    if self._stop_event.is_set():
                        # 如果收到停止信号，取消剩余任务
                        for f in future_to_index:
                            if not f.done():
                                f.cancel()
                        break
                    
                    index = future_to_index[future]
                    try:
                        success = future.result()
                        if success:
                            self.success_count += 1
                        else:
                            self.fail_count += 1
                            
                        self.processed_count += 1
                        
                        # 更新进度
                        progress = (self.processed_count / self.total_files) * 100
                        self._update_progress(progress)
                        
                        # 更新状态
                        if self.processed_count % 5 == 0 or self.processed_count == self.total_files:
                            self._update_status(
                                f"已处理 {self.processed_count}/{self.total_files} 个文件 "
                                f"(成功: {self.success_count}, 失败: {self.fail_count})"
                            )
                            
                    except Exception as e:
                        self.fail_count += 1
                        self.processed_count += 1
                        logger.error(f"任务处理异常: {str(e)}")
            
            # 处理完成
            if self._stop_event.is_set():
                self._update_status(f"批处理已停止，已处理 {self.processed_count}/{self.total_files} 个文件")
                self._update_progress((self.processed_count / self.total_files) * 100)
            else:
                self._update_progress(100)
                self._update_status(
                    f"批量处理完成！成功: {self.success_count}, 失败: {self.fail_count}, "
                    f"总计: {self.total_files}"
                )
            
            # 调用完成回调
            if self.completion_callback:
                self.completion_callback(self.success_count, self.fail_count)
                
        except Exception as e:
            error_msg = f"批处理过程发生异常: {str(e)}"
            logger.error(error_msg)
            self._update_status(error_msg)
            if self.completion_callback:
                self.completion_callback(self.success_count, self.fail_count)
        finally:
            self._is_running = False


class PDFCrackApp:
    """PDF破解工具的图形用户界面应用"""
    
    def __init__(self, root):
        """初始化GUI应用
        
        Args:
            root: Tkinter根窗口对象
        """
        self.root = root
        self.root.title("PDF限制移除工具")
        self.root.geometry("700x750")
        # 允许窗口最大化
        self.root.resizable(True, True)
        
        # 设置中文字体支持
        self._set_fonts()
        
        # 创建主框架
        self.main_frame = ttk.Frame(root, padding="20")
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 初始化变量
        self.input_file_var = tk.StringVar()
        self.output_file_var = tk.StringVar()
        self.batch_files = []  # 存储批量处理的文件列表
        self.is_processing = False  # 标记是否正在处理
        self.batch_processor = None  # 批处理器实例
        
        # 创建界面元素
        self._create_widgets()
        
        # 设置样式
        self._set_style()
        
        # 添加停止批处理按钮
        self._add_stop_button()
        
        # 设置窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self._on_closing)

    def _on_closing(self):
        """窗口关闭时的处理"""
        if self.batch_processor and self.batch_processor.is_running():
            if messagebox.askokcancel("退出", "批处理正在运行，确定要退出吗？"):
                self.batch_processor.stop()
                self.root.destroy()
        else:
            self.root.destroy()

    def _add_stop_button(self):
        """添加停止批处理按钮"""
        if hasattr(self, 'process_buttons_frame'):
            self.stop_button = ttk.Button(
                self.process_buttons_frame, 
                text="停止处理", 
                command=self._stop_processing,
                width=15, 
                state=tk.DISABLED
            )
            self.stop_button.pack(side=tk.LEFT, padx=(10, 0))
    
    def _stop_processing(self):
        """停止批处理操作"""
        if self.batch_processor and self.batch_processor.is_running():
            self.batch_processor.stop()
            self._update_status("正在停止批处理，请稍候...")
            
            # 禁用停止按钮，防止重复点击
            self.stop_button.config(state=tk.DISABLED)
    
    def _set_fonts(self):
        """设置中文字体支持"""
        try:
            # 尝试设置中文字体
            default_font = tk.font.nametofont("TkDefaultFont")
            default_font.configure(family="SimHei", size=10)
            text_font = tk.font.nametofont("TkTextFont")
            text_font.configure(family="SimHei", size=10)
            fixed_font = tk.font.nametofont("TkFixedFont")
            fixed_font.configure(family="SimHei", size=10)
        except Exception:
            # 字体设置失败时忽略错误
            pass
    
    def _set_style(self):
        """设置界面样式"""
        style = ttk.Style()
        # 设置按钮样式
        style.configure("TButton", font=("SimHei", 10))
        # 设置标签样式
        style.configure("TLabel", font=("SimHei", 10))
        # 设置进度条样式
        style.configure("TProgressbar", length=200)
        
    def _create_widgets(self):
        """创建GUI界面元素"""
        # 标题标签
        title_label = ttk.Label(
            self.main_frame, 
            text="PDF限制移除工具", 
            font=("SimHei", 16, "bold")
        )
        title_label.pack(pady=(0, 20))
        
        # 输入文件选择
        input_frame = ttk.Frame(self.main_frame)
        input_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(input_frame, text="输入PDF文件:").pack(anchor=tk.W, pady=(0, 5))
        
        input_file_frame = ttk.Frame(input_frame)
        input_file_frame.pack(fill=tk.X)
        
        ttk.Entry(input_file_frame, textvariable=self.input_file_var, width=50).pack(side=tk.LEFT, fill=tk.X, expand=True)
        
        button_frame = ttk.Frame(input_file_frame)
        button_frame.pack(side=tk.RIGHT)
        
        ttk.Button(button_frame, text="浏览...", command=self._browse_input_file).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(button_frame, text="批量添加", command=self._browse_batch_files).pack(side=tk.LEFT)
        
        # 批量文件列表
        batch_frame = ttk.LabelFrame(self.main_frame, text="批量文件列表")
        batch_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        # 创建列表视图
        columns = ("文件名", "路径", "状态")
        self.file_tree = ttk.Treeview(batch_frame, columns=columns, show="headings", selectmode="extended")
        
        # 设置列宽和标题
        self.file_tree.heading("文件名", text="文件名")
        self.file_tree.heading("路径", text="路径")
        self.file_tree.heading("状态", text="状态")
        
        self.file_tree.column("文件名", width=150, anchor=tk.W)
        self.file_tree.column("路径", width=300, anchor=tk.W)
        self.file_tree.column("状态", width=100, anchor=tk.CENTER)
        
        self.file_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 0), pady=5)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(batch_frame, orient=tk.VERTICAL, command=self.file_tree.yview)
        self.file_tree.configure(yscroll=scrollbar.set)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5)
        
        # 批量操作按钮
        batch_op_frame = ttk.Frame(self.main_frame)
        batch_op_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Button(batch_op_frame, text="移除选中", command=self._remove_selected_files).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(batch_op_frame, text="清空列表", command=self._clear_file_list).pack(side=tk.LEFT)
        
        # 输出目录选择（批量处理时使用）
        output_dir_frame = ttk.Frame(self.main_frame)
        output_dir_frame.pack(fill=tk.X, pady=(0, 20))
        
        ttk.Label(output_dir_frame, text="输出目录:").pack(anchor=tk.W, pady=(0, 5))
        
        output_dir_file_frame = ttk.Frame(output_dir_frame)
        output_dir_file_frame.pack(fill=tk.X)
        
        self.output_dir_var = tk.StringVar()
        ttk.Entry(output_dir_file_frame, textvariable=self.output_dir_var, width=50).pack(side=tk.LEFT, fill=tk.X, expand=True)
        ttk.Button(output_dir_file_frame, text="浏览...", command=self._browse_output_dir).pack(side=tk.RIGHT, padx=(10, 0))
        
        # 处理按钮
        self.process_buttons_frame = ttk.Frame(self.main_frame)
        self.process_buttons_frame.pack(pady=10)
        
        self.process_single_button = ttk.Button(
            self.process_buttons_frame, 
            text="处理单个文件", 
            command=self._process_single_file,
            width=15
        )
        self.process_single_button.pack(side=tk.LEFT, padx=(0, 10))
        
        self.process_batch_button = ttk.Button(
            self.process_buttons_frame, 
            text="批量处理", 
            command=self._process_batch_files,
            width=15
        )
        self.process_batch_button.pack(side=tk.LEFT)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(
            self.main_frame, 
            variable=self.progress_var, 
            length=400, 
            mode="determinate"
        )
        self.progress_bar.pack(pady=(10, 0))
        
        # 状态文本框
        status_label = ttk.Label(self.main_frame, text="操作日志:")
        status_label.pack(anchor=tk.W, pady=(20, 5))
        
        self.status_text = scrolledtext.ScrolledText(self.main_frame, height=8, width=70, wrap=tk.WORD)
        self.status_text.pack(fill=tk.BOTH, expand=True)
        self.status_text.config(state=tk.DISABLED)
        
        # 版本信息
        version_label = ttk.Label(self.main_frame, text="版本: 1.0.0", font=("SimHei", 8))
        version_label.pack(side=tk.RIGHT, pady=(10, 0))
    
    def _browse_input_file(self):
        """浏览选择输入PDF文件"""
        file_path = filedialog.askopenfilename(
            title="选择PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        
        if file_path:
            self.input_file_var.set(file_path)
            # 自动生成输出文件路径
            base_name, ext = os.path.splitext(file_path)
            output_file = f"{base_name}(已破解){ext}"
            self.output_file_var.set(output_file)
            self._update_status(f"已选择输入文件: {file_path}")
    
    def _browse_batch_files(self):
        """浏览选择多个PDF文件进行批量处理"""
        file_paths = filedialog.askopenfilenames(
            title="选择多个PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        
        if file_paths:
            self._add_files_to_batch(file_paths)
            self._update_status(f"已添加 {len(file_paths)} 个文件到批量处理列表")
    
    def _browse_output_dir(self):
        """浏览选择输出目录"""
        dir_path = filedialog.askdirectory(title="选择输出目录")
        
        if dir_path:
            self.output_dir_var.set(dir_path)
            self._update_status(f"已选择输出目录: {dir_path}")
    
    def _add_files_to_batch(self, file_paths: List[str]):
        """添加文件到批量处理列表
        
        Args:
            file_paths: 文件路径列表
        """
        for file_path in file_paths:
            if file_path not in [file[0] for file in self.batch_files]:
                file_name = os.path.basename(file_path)
                file_dir = os.path.dirname(file_path)
                self.batch_files.append((file_path, "等待处理"))
                item_id = self.file_tree.insert("", tk.END, values=(file_name, file_dir, "等待处理"))
                
                # 设置状态颜色
                self.file_tree.tag_configure("等待处理", foreground="black")
                self.file_tree.tag_configure("处理中", foreground="blue")
                self.file_tree.tag_configure("成功", foreground="green")
                self.file_tree.tag_configure("失败", foreground="red")
                self.file_tree.item(item_id, tags=("等待处理",))
    
    def _remove_selected_files(self):
        """移除选中的文件"""
        selected_items = self.file_tree.selection()
        if not selected_items:
            messagebox.showinfo("提示", "请先选择要移除的文件")
            return
        
        # 从后往前删除，避免索引变化
        for item in reversed(selected_items):
            item_values = self.file_tree.item(item, "values")
            file_name, file_dir, status = item_values
            
            # 从批量文件列表中移除
            for i, (file_path, _) in enumerate(self.batch_files):
                if (os.path.basename(file_path) == file_name and 
                    os.path.dirname(file_path) == file_dir):
                    del self.batch_files[i]
                    break
            
            # 从树形视图中移除
            self.file_tree.delete(item)
        
        self._update_status(f"已移除 {len(selected_items)} 个文件")
    
    def _clear_file_list(self):
        """清空文件列表"""
        if not self.batch_files:
            return
            
        if messagebox.askyesno("确认", "确定要清空所有文件吗？"):
            self.file_tree.delete(*self.file_tree.get_children())
            self.batch_files.clear()
            self._update_status("已清空文件列表")
    
    def _process_single_file(self):
        """处理单个PDF文件"""
        input_file = self.input_file_var.get()
        
        # 检查输入文件是否已选择
        if not input_file:
            messagebox.showerror("错误", "请选择输入PDF文件")
            return
        
        # 禁用处理按钮，防止重复点击
        self.process_single_button.config(state=tk.DISABLED)
        self.process_batch_button.config(state=tk.DISABLED)
        self.progress_var.set(0)
        
        # 在新线程中处理单个文件
        def process_in_thread():
            try:
                # 更新状态
                self._update_status(f"开始处理文件: {os.path.basename(input_file)}")
                self.root.after(0, lambda: self.progress_var.set(20))
                
                # 自动生成输出文件路径
                base_name, ext = os.path.splitext(input_file)
                output_file = f"{base_name}(已破解){ext}"
                
                # 执行PDF破解操作
                result_file = pdf_crack(input_file, output_file)
                
                self.root.after(0, lambda: self.progress_var.set(100))
                
                # 显示成功信息
                success_msg = f"PDF限制已成功移除！\n输出文件: {os.path.basename(result_file)}"
                self._update_status(success_msg)
                self.root.after(0, lambda: messagebox.showinfo("成功", success_msg))
                
            except Exception as e:
                # 显示错误信息
                error_msg = f"处理失败: {str(e)}"
                self._update_status(error_msg)
                logger.error(error_msg)
                self.root.after(0, lambda: messagebox.showerror("错误", error_msg))
            finally:
                # 恢复处理按钮状态
                self.root.after(0, lambda: self.process_single_button.config(state=tk.NORMAL))
                self.root.after(0, lambda: self.process_batch_button.config(state=tk.NORMAL))
        
        # 启动处理线程
        thread = threading.Thread(target=process_in_thread, daemon=True)
        thread.start()
    
    def _process_batch_files(self):
        """批量处理PDF文件"""
        if not self.batch_files:
            messagebox.showerror("错误", "批量文件列表为空，请先添加文件")
            return
        
        output_dir = self.output_dir_var.get()
        if not output_dir:
            # 如果未选择输出目录，使用第一个文件的目录
            if self.batch_files:
                output_dir = os.path.dirname(self.batch_files[0][0])
                self.output_dir_var.set(output_dir)
            else:
                messagebox.showerror("错误", "请选择输出目录")
                return
        
        # 检查输出目录是否存在
        if not check_folder(output_dir):
            messagebox.showerror("错误", f"无法创建输出目录: {output_dir}")
            return
        
        # 禁用处理按钮，防止重复点击
        self.process_single_button.config(state=tk.DISABLED)
        self.process_batch_button.config(state=tk.DISABLED)
        if hasattr(self, 'stop_button'):
            self.stop_button.config(state=tk.NORMAL)
        self.progress_var.set(0)
        
        # 创建并启动批处理器
        self.batch_processor = BatchProcessor(
            files=self.batch_files,
            output_dir=output_dir,
            progress_callback=self._on_batch_progress,
            status_callback=self._update_status,
            file_status_callback=self._update_file_status,
            completion_callback=self._on_batch_completion
        )
        self.batch_processor.start()
    
    def _on_batch_progress(self, progress: float):
        """批处理进度更新回调"""
        # 使用after确保在主线程中更新UI
        self.root.after(0, lambda: self.progress_var.set(progress))
    
    def _on_batch_completion(self, success_count: int, fail_count: int):
        """批处理完成回调"""
        # 使用after确保在主线程中更新UI
        self.root.after(0, lambda: self.process_single_button.config(state=tk.NORMAL))
        self.root.after(0, lambda: self.process_batch_button.config(state=tk.NORMAL))
        if hasattr(self, 'stop_button'):
            self.root.after(0, lambda: self.stop_button.config(state=tk.DISABLED))
        
        # 显示处理结果
        result_msg = f"批量处理完成！成功: {success_count} 个，失败: {fail_count} 个"
        self._update_status(result_msg)
        self.root.after(0, lambda: messagebox.showinfo("批量处理完成", result_msg))
    
    def _update_file_status(self, index: int, status: str):
        """更新文件状态
        
        Args:
            index: 文件索引
            status: 状态文本
        """
        # 使用after确保在主线程中更新UI
        def update_ui():
            if index < len(self.batch_files):
                # 更新内存中的状态
                file_path, _ = self.batch_files[index]
                self.batch_files[index] = (file_path, status)
                
                # 更新界面上的状态
                if index < len(self.file_tree.get_children()):
                    item = self.file_tree.get_children()[index]
                    values = list(self.file_tree.item(item, "values"))
                    values[2] = status
                    self.file_tree.item(item, values=values, tags=(status,))
        
        self.root.after(0, update_ui)
    
    def _update_status(self, message: str):
        """更新状态文本框
        
        Args:
            message: 要显示的消息
        """
        # 使用after确保在主线程中更新UI
        def update_ui():
            # 获取当前时间
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            log_message = f"[{current_time}] {message}\n"
            
            self.status_text.config(state=tk.NORMAL)
            self.status_text.insert(tk.END, log_message)
            # 自动滚动到底部
            self.status_text.see(tk.END)
            self.status_text.config(state=tk.DISABLED)
        
        self.root.after(0, update_ui)


def main() -> None:
    """主函数，处理命令行参数并执行PDF破解操作或启动GUI界面"""
    # 检查是否有命令行参数，如果有则使用命令行模式，否则启动GUI
    if len(sys.argv) > 1:
        # 创建命令行参数解析器
        parser = argparse.ArgumentParser(description='移除PDF文件的编辑限制')
        parser.add_argument('input_file', nargs='?', help='输入的PDF文件路径')
        parser.add_argument('-o', '--output', help='输出的PDF文件路径')
        parser.add_argument('-b', '--batch', nargs='+', help='批量处理的PDF文件路径列表')
        parser.add_argument('-d', '--dir', help='批量处理的输出目录')
        parser.add_argument('-v', '--version', action='version', version='PDF Crack 1.0.0')
        
        # 解析命令行参数
        args = parser.parse_args()
        
        try:
            # 批量处理模式
            if args.batch:
                # 处理*.pdf通配符
                if args.batch and args.batch[0].endswith('*.pdf'):
                    import glob
                    args.batch = glob.glob(args.batch[0])
                
                if not args.dir:
                    # 如果未指定输出目录，使用第一个文件的目录
                    args.dir = os.path.dirname(args.batch[0]) if args.batch else "."
                    print(f"未指定输出目录，使用默认目录: {args.dir}")
                
                # 检查输出目录是否存在
                if not check_folder(args.dir):
                    print(f"创建输出目录失败: {args.dir}")
                    sys.exit(1)
                
                # 创建批处理器并执行
                batch_processor = BatchProcessor(
                    files=[(f, "等待处理") for f in args.batch],
                    output_dir=args.dir,
                    status_callback=lambda msg: print(f"[INFO] {msg}"),
                    progress_callback=lambda p: print(f"进度: {p:.1f}%", end='\r')
                )
                
                print(f"开始批量处理 {len(args.batch)} 个文件...")
                batch_processor.start()
                
                # 等待处理完成
                while batch_processor.is_running():
                    time.sleep(0.5)
                
                print(f"\n批量处理完成！成功: {batch_processor.success_count}, 失败: {batch_processor.fail_count}")
                
            # 单个文件处理模式
            elif args.input_file:
                pdf_crack(args.input_file, args.output)
                print(f"PDF限制已成功移除！输出文件: {args.output or args.input_file.replace('.pdf', '(已破解).pdf')}")
            else:
                parser.print_help()
                
        except Exception as e:
            # 处理所有异常并显示友好的错误信息
            print(f"错误: {str(e)}", file=sys.stderr)
            logger.error(f"命令行执行错误: {str(e)}")
            sys.exit(1)
    else:
        # 没有命令行参数，启动GUI界面
        root = tk.Tk()
        # 设置中文字体支持
        try:
            root.option_add("*Font", "SimHei 10")
        except Exception:
            pass
        app = PDFCrackApp(root)
        root.mainloop()


if __name__ == '__main__':
    main()